package com.sz.biz.logistics.ord.service.impl;

import com.sz.biz.common.base.entity.ExchangeRate;
import com.sz.biz.common.base.service.ExchangeRateService;
import com.sz.biz.csr.service.CsrWorkOrderSchemaService;
import com.sz.biz.csr.service.impl.CsrWorkOrderSchemaServiceImpl;
import com.sz.biz.logistics.billing.dto.OrderCalcResult;
import com.sz.biz.logistics.billing.dto.QuotationCalcObject;
import com.sz.biz.logistics.billing.dto.QuotationCalcResult;
import com.sz.biz.logistics.billing.service.QuotationCalcService;
import com.sz.biz.logistics.constants.QuotationConstants;
import com.sz.biz.logistics.ord.entity.*;
import com.sz.biz.logistics.ord.service.*;
import com.sz.common.base.exception.BizException;
import com.sz.common.base.service.AbstractService;
import com.sz.common.core.service.PrincipalUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;

/**
 * Function: OrdCalcJobService <br>
 * Author: wentao.chang <br>
 * Date: 2017-05-18 18:46:00
 */

@org.springframework.stereotype.Service("orderCalcJobService")
public class OrderCalcJobServiceImpl extends AbstractService implements OrderCalcJobService {

    @Autowired
    private OrdOrderService ordOrderService;

    @Autowired
    private OrdOrderAddressService orderAddressService;

    @Autowired
    private OrdServiceBillService ordServiceBillService;

    @Autowired
    private OrdServiceBillHistoryService ordServiceBillHistoryService;

    @Autowired
    private QuotationCalcService quotationCalcService;

    @Autowired
    private ExchangeRateService exchangeRateService;

    @Autowired
    private CsrWorkOrderSchemaService csrWorkOrderSchemaService;

    /**
     * @param type 1采购价 2销售价
     * @throws ExecutionException   e1
     * @throws InterruptedException e2
     */
    @Override
    public void calcCron(int type) throws ExecutionException, InterruptedException {
        //获取2个月内没有进行计算的订单
        List<OrdOrder> orders = ordOrderService.findNoCalcedWaybills(type);
        List<String> orderNos = new ArrayList<>();
        orders.forEach(ordOrder -> orderNos.add(ordOrder.getOrderNo()));
        //获取地址信息
        List<OrdOrderAddress> orderAddressList = orderAddressService.findByOrderNos(orderNos);
        Map<String, OrdOrderAddress> orderAddressMap = new HashMap<>();
        orderAddressList.forEach(orderAddress -> orderAddressMap.put(orderAddress.getOrderNo(), orderAddress));

        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(10);

        List<Future<Object>> futures = new ArrayList<>();
        for (OrdOrder order : orders) {
            Callable c1 = new WayBillCalcCallable(order, orderAddressMap.get(order.getOrderNo()), type);
            //执行任务并获取Future对象
            futures.add(pool.submit(c1));
        }
        for (Future<Object> future : futures) {
            future.get();
        }
        pool.shutdown();
    }

    private class WayBillCalcCallable implements Callable {
        private OrdOrder ordOrder;
        private OrdOrderAddress orderAddress;
        private int type;

        WayBillCalcCallable(OrdOrder ordOrder, OrdOrderAddress orderAddress, int type) {
            this.ordOrder = ordOrder;
            this.orderAddress = orderAddress;
            this.type = type;
        }

        @Override
        public Integer call() throws Exception {
            calcOrdOrder(ordOrder, orderAddress, 1, type);
            return 0;
        }
    }


    /**
     * 计算所有未计费订单
     */
    @Override
    public void calcExchangeRateCron() throws ExecutionException, InterruptedException {
        List<OrdServiceBill> bills = ordServiceBillService.findExchangeRateEmpty();

        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(10);

        List<Future<Object>> futures = new ArrayList<>();
        for (OrdServiceBill bill : bills) {
            Callable c1 = new WayBillCalcExchangeCallable(bill);
            //执行任务并获取Future对象
            futures.add(pool.submit(c1));
        }
        for (Future<Object> future : futures) {
            future.get();
        }
        pool.shutdown();

    }

    private class WayBillCalcExchangeCallable implements Callable {
        private OrdServiceBill bill;

        WayBillCalcExchangeCallable(OrdServiceBill bill) {
            this.bill = bill;
        }

        @Override
        public Integer call() throws Exception {
            calcOrdOrderExchange(bill);
            return 0;
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void calcOrdOrderExchange(OrdServiceBill bill) {
        ExchangeRate exchangeRate = exchangeRateService.findCurrencyRoeByDate(bill.getCurrencyCode(),
                bill.getCustCurrencyCode(), bill.getBillTime());
        if (exchangeRate != null) {
            bill.setCustCurrencyAmount(bill.getAmountDue().multiply(exchangeRate.getRate()));
            bill.setExchangeRate(exchangeRate.getRate());
            ordServiceBillService.updateExchangeRate(bill);
        }
    }


    /**
     * 按订单计费
     *
     * @param orderNo orderNo
     * @param type    1采购价 2销售价  QuotationConstants.Type.COST
     */
    @Override
    public OrderCalcResult calcOrdOrder(String orderNo, int type) {
        OrdOrder ordOrder = ordOrderService.findByOrderNo(orderNo);
        OrdOrderAddress ordOrderAddress = orderAddressService.findByOrderNo(orderNo);
        return calcOrdOrder(ordOrder, ordOrderAddress, 2, type);
    }

    /**
     * 按订单计费
     *
     * @param ordOrder     ordOrder
     * @param orderAddress orderAddress
     * @param calcType     1定时任务 2.手工点击
     * @param type         1采购价 2销售价
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public OrderCalcResult calcOrdOrder(OrdOrder ordOrder, OrdOrderAddress orderAddress, int calcType, int type) {
        String errorMsg = "";
        if (type == QuotationConstants.Type.COST) {
            QuotationCalcObject cost = null;
            try {
                cost = quotationCalcService.calcOrderCostPrice(ordOrder, orderAddress);
            } catch (BizException e) {
                if (e.getData() instanceof QuotationCalcObject) {
                    cost = (QuotationCalcObject) e.getData();
                    cost.getResult().clear();
                }
                errorMsg = e.getMsg();
            }
            if (cost != null) {
                List<QuotationCalcResult> results = cost.getResult();
                boolean isSucceeded = false;
                for (QuotationCalcResult result : results) {
                    if (result.isHasResult()) {
                        isSucceeded = true;
                    } else {
                        isSucceeded = false;
                        break;
                    }
                }

                BigDecimal amount = BigDecimal.ZERO;
                String currency = "";
                boolean isBilled = false;
                List<OrdServiceBill> bills = ordServiceBillService.findByOrderNoAndType(ordOrder.getOrderNo(), type);
                for (OrdServiceBill bill : bills) {
                    if (bill.getIsBilled()) {
                        isBilled = true;
                        break;
                    }
                }
                //写job成本的表
                OrderCalcJob ocjcost = new OrderCalcJob();
                ocjcost.setFeeTime(cost.getOrderDate());
                String calcMsgs = errorMsg + cost.getCalcMsgs().toString();
                ocjcost.setCalcMsg(calcMsgs.length() > 4096 ? calcMsgs.substring(0, 4096) : calcMsgs);
                ocjcost.setCalcType(calcType);
                //采购价
                ocjcost.setType(QuotationConstants.Type.COST);
                ocjcost.setIsSucceeded(isSucceeded);
                ocjcost.setOrderNo(cost.getOrderNo());

                //起始地
                ocjcost.setFromCountry(orderAddress.getFromCountry());
                ocjcost.setFromProvince(orderAddress.getFromProvince());
                ocjcost.setFromDistrict(orderAddress.getFromDistrict());
                ocjcost.setFromCity(orderAddress.getFromCity());
                ocjcost.setFromStreet(orderAddress.getFromStreet());
                ocjcost.setFromAddress(orderAddress.getFromAddress());


                //目的地
                ocjcost.setToCountry(orderAddress.getToCountry());
                ocjcost.setToProvince(orderAddress.getToProvince());
                ocjcost.setToCity(orderAddress.getToCity());
                ocjcost.setToStreet(orderAddress.getToStreet());
                ocjcost.setToAddress(orderAddress.getToAddress());

                //揽收地址
                ocjcost.setFetchCountry(orderAddress.getFetchCountry());
                ocjcost.setFetchProvince(orderAddress.getFetchProvince());
                ocjcost.setFetchCity(orderAddress.getFetchCity());
                ocjcost.setFetchDistrict(orderAddress.getFetchDistrict());
                ocjcost.setFetchStreet(orderAddress.getFetchStreet());
                ocjcost.setFetchAddress(orderAddress.getFetchAddress());

                //货物类型
                ocjcost.setCargoType(ordOrder.getCargoType());


                insert(ocjcost);

                if (isSucceeded) {
                    // 只要成功就记录计费历史表
                    for (QuotationCalcResult result : results) {
                        if (result.isHasResult()) {
                            OrdServiceBill ordServiceBill = new OrdServiceBill();
                            ordServiceBill.setSupplierId(result.getSupplierId());
                            ordServiceBill.setType(QuotationConstants.Type.COST);
                            getOrdServiceBill(cost, result, ordServiceBill, ocjcost.getId());
                            ordServiceBillHistoryService.save(ordServiceBill);
                            amount = amount.add(result.getAmount());
                            currency = result.getCurrencyCode();
                        }
                    }

                    //没有生成账单就去更新账单ord_service_bill
                    if (!isBilled) {
                        //先删除
                        ordServiceBillService.deleteByOrderNoAndType(ordOrder.getOrderNo(), type);
                        //再插入
                        for (QuotationCalcResult result : results) {
                            if (result.isHasResult()) {
                                OrdServiceBill ordServiceBill = new OrdServiceBill();
                                ordServiceBill.setSupplierId(result.getSupplierId());
                                ordServiceBill.setType(QuotationConstants.Type.COST);
                                getOrdServiceBill(cost, result, ordServiceBill, ocjcost.getId());
                                ordServiceBillService.save(ordServiceBill);
                            }
                        }
                    }
                }

                OrderCalcResult qcr = new OrderCalcResult();
                qcr.setSuccessed(isSucceeded);
                qcr.setAmount(amount);
                qcr.setCurrency(currency);
                return qcr;
            }
        }
        if (type == QuotationConstants.Type.SELLING) {
            QuotationCalcObject sale = null;
            errorMsg = "";
            boolean isFromPre = false;
            try {
                if (OrderStatus.RECEGOOD.compareTo(ordOrder.getOrderStatus()) > 0) {
                    isFromPre = true;
                }
                sale = quotationCalcService.calcOrderSalePrice(ordOrder, orderAddress, isFromPre);
            } catch (BizException e) {
                if (e.getData() instanceof QuotationCalcObject) {
                    sale = (QuotationCalcObject) e.getData();
                    sale.getResult().clear();
                }
                errorMsg = e.getMsg();
            }

            if (sale != null) {
                List<QuotationCalcResult> results = sale.getResult();
                boolean isSucceeded = false;

                for (QuotationCalcResult result : results) {
                    if (result.isHasResult()) {
                        isSucceeded = true;
                    } else {
                        isSucceeded = false;
                        break;
                    }
                }
                BigDecimal amount = BigDecimal.ZERO;
                String currency = "";
                boolean isBilled = false;
                List<OrdServiceBill> bills = ordServiceBillService.findByOrderNoAndType(ordOrder.getOrderNo(), type);
                for (OrdServiceBill bill : bills) {
                    if (bill.getIsBilled()) {
                        isBilled = true;
                        break;
                    }
                }

                //写job销售的表
                OrderCalcJob ocjsale = new OrderCalcJob();
                ocjsale.setFeeTime(sale.getOrderDate());
                String calcMsgs = errorMsg + sale.getCalcMsgs().toString();
                ocjsale.setCalcMsg(calcMsgs.length() > 4096 ? calcMsgs.substring(0, 4096) : calcMsgs);
                ocjsale.setCalcType(calcType);
                //销售价
                ocjsale.setType(QuotationConstants.Type.SELLING);
                ocjsale.setIsSucceeded(isSucceeded);
                ocjsale.setOrderNo(sale.getOrderNo());


                //起始地
                ocjsale.setFromCountry(orderAddress.getFromCountry());
                ocjsale.setFromProvince(orderAddress.getFromProvince());
                ocjsale.setFromDistrict(orderAddress.getFromDistrict());
                ocjsale.setFromCity(orderAddress.getFromCity());
                ocjsale.setFromStreet(orderAddress.getFromStreet());
                ocjsale.setFromAddress(orderAddress.getFromAddress());


                //目的地
                ocjsale.setToCountry(orderAddress.getToCountry());
                ocjsale.setToProvince(orderAddress.getToProvince());
                ocjsale.setToCity(orderAddress.getToCity());
                ocjsale.setToStreet(orderAddress.getToStreet());
                ocjsale.setToAddress(orderAddress.getToAddress());

                //揽收地址
                ocjsale.setFetchCountry(orderAddress.getFetchCountry());
                ocjsale.setFetchProvince(orderAddress.getFetchProvince());
                ocjsale.setFetchCity(orderAddress.getFetchCity());
                ocjsale.setFetchDistrict(orderAddress.getFetchDistrict());
                ocjsale.setFetchStreet(orderAddress.getFetchStreet());
                ocjsale.setFetchAddress(orderAddress.getFetchAddress());

                //货物类型
                ocjsale.setCargoType(ordOrder.getCargoType());

                insert(ocjsale);

                //计费成功并且不是预估费用
                if (isSucceeded) {
                    for (QuotationCalcResult result : results) {
                        if (result.isHasResult()) {
                            amount = amount.add(result.getAmount());
                            currency = result.getCurrencyCode();
                        }
                    }

                    // 只要成功就记录计费历史表
                    if (!isFromPre) {
                        for (QuotationCalcResult result : results) {
                            if (result.isHasResult()) {
                                OrdServiceBill ordServiceBill = new OrdServiceBill();
                                ordServiceBill.setSupplierId(result.getSupplierId());
                                ordServiceBill.setType(QuotationConstants.Type.SELLING);
                                getOrdServiceBill(sale, result, ordServiceBill, ocjsale.getId());
                                ordServiceBillHistoryService.save(ordServiceBill);
                            }
                        }
                    }

                    //创建工单
                    if (isBilled) {
                        String title = "订单" + ordOrder.getOrderNo() + "已经生成账单";
                        String content = "订单" + ordOrder.getOrderNo() + "已经生成账单";
                        csrWorkOrderSchemaService.saveCsrWorkOrderSchemaByOrd(ordOrder, title, content,
                                CsrWorkOrderSchemaServiceImpl.WORK_ORDER_SCHEMA_TYPE_WAYBILL);
                    }
                    //没有生成账单就去更新账单ord_service_bill
                    if (!isFromPre && !isBilled) {
                        //先删除
                        ordServiceBillService.deleteByOrderNoAndType(ordOrder.getOrderNo(), type);
                        //再插入
                        for (QuotationCalcResult result : results) {
                            OrdServiceBill ordServiceBill = new OrdServiceBill();
                            ordServiceBill.setCustomerId(sale.getCustomerId());
                            ordServiceBill.setType(QuotationConstants.Type.SELLING);
                            getOrdServiceBill(sale, result, ordServiceBill, ocjsale.getId());
                            ordServiceBillService.save(ordServiceBill);
                        }
                    }

                }


                OrderCalcResult qcr = new OrderCalcResult();
                qcr.setSuccessed(isSucceeded);
                qcr.setAmount(amount);
                qcr.setCurrency(currency);
                return qcr;
            }
        }
        return null;
    }

    private void getOrdServiceBill(QuotationCalcObject sale, QuotationCalcResult result, OrdServiceBill ordServiceBill,
                                   Integer jobId) {
        ordServiceBill.setAmountDue(result.getAmount());
        ordServiceBill.setBillTime(sale.getOrderDate());
        ordServiceBill.setRegionId(result.getRegionId());
        ordServiceBill.setWeightSchemaId(result.getWeightSchemaId());
        ordServiceBill.setOrderNo(sale.getOrderNo());
        ordServiceBill.setProductId(result.getProductId());
        ordServiceBill.setProductUid(result.getProductUid());
        ordServiceBill.setQuotationId(result.getQuotationId());
        ordServiceBill.setQuotationUid(result.getQuotationUid());
        ordServiceBill.setServiceId(result.getServiceId());
        ordServiceBill.setServiceUid(result.getServiceUid());
        ordServiceBill.setFeeTypeId(result.getFeeTypeId());
        ordServiceBill.setIsBilled(false);
        ordServiceBill.setCurrencyCode(result.getCurrencyCode());
        ordServiceBill.setCustCurrencyCode(result.getCustCurrencyCode());
        ordServiceBill.setCustCurrencyAmount(result.getCustCurrencyAmount());
        ordServiceBill.setExchangeRate(result.getExchangeRate());
        ordServiceBill.setJobId(jobId);
        ordServiceBill.setFeeWeight(result.getFeeWeight());
        ordServiceBill.setFeeWeightUnit(result.getFeeWeightUnitCode());

    }


    @Override
    protected String getMapperNamespace() {
        return "OrderCalcJobMapper";
    }


    /**
     * 插入计费信息
     *
     * @param job job
     */
    @Override
    public void insert(OrderCalcJob job) {
        int accountId = 0;
        try {
            accountId = PrincipalUtils.getAccountId();
        } catch (Exception e) {
            //do nothing
        }
        job.setWorkerId(accountId);
        job.setFeeCalcTime(new Date());
        dao.save("OrderCalcJobMapper.insert", job);
    }

    /**
     * 按订单号以及费用类型获取已有的计费历史
     *
     * @param orderNo
     * @param feeType
     */
    @Override
    public List<OrderCalcJob> findByOrderNoAndType(String orderNo, int feeType) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderNo", orderNo);
        map.put("type", feeType);
        return dao.findForList("OrderCalcJobMapper.findByOrderNoAndType", map, OrderCalcJob.class);
    }

    /**
     * 按订单号获取已有的计费历史
     *
     * @param orderNo
     */
    @Override
    public List<OrderCalcJob> findByOrderNo(String orderNo) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderNo", orderNo);
        return dao.findForList("OrderCalcJobMapper.findByOrderNo", map, OrderCalcJob.class);
    }

}